package com.ruoyi.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.system.Utils.DataHandler.FilePortDataHandler;
import com.ruoyi.system.Utils.DataHandler.PortDataHandler;
import com.ruoyi.system.Utils.USBUtils;
import com.ruoyi.system.domain.DataFrame;
import com.ruoyi.system.mapper.DataFrameMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.harmony.pack200.FileBands;
import org.springframework.stereotype.Service;
import com.ruoyi.system.domain.bo.DocumentBo;
import com.ruoyi.system.domain.vo.DocumentVo;
import com.ruoyi.system.domain.Document;
import com.ruoyi.system.mapper.DocumentMapper;
import com.ruoyi.system.service.IDocumentService;

import javax.usb.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 文件信息Service业务层处理
 *
 * @author ruoyi
 * @date 2024-06-30
 */
@RequiredArgsConstructor
@Service
public class DocumentServiceImpl implements IDocumentService {

    private final DocumentMapper baseMapper;
    private final DataFrameMapper dataFrameMapper;

    static byte fileId0 = 0;

    /**
     * 查询文件信息
     */
    @Override
    public DocumentVo queryById(Long documentId){
        return baseMapper.selectVoById(documentId);
    }

    /**
     * 查询文件信息列表
     */
    @Override
    public TableDataInfo<DocumentVo> queryPageList(DocumentBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Document> lqw = buildQueryWrapper(bo);
        Page<DocumentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询文件信息列表
     */
    @Override
    public List<DocumentVo> queryList(DocumentBo bo) {
        LambdaQueryWrapper<Document> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Document> buildQueryWrapper(DocumentBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Document> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getDocumentId() != null, Document::getDocumentId, bo.getDocumentId());
        lqw.eq(StringUtils.isNotBlank(bo.getDocuLength()), Document::getDocuLength, bo.getDocuLength());
        lqw.eq(bo.getStartTime() != null, Document::getStartTime, bo.getStartTime());
        lqw.eq(bo.getEndTime() != null, Document::getEndTime, bo.getEndTime());
        return lqw;
    }

    /**
     * 新增文件信息
     */
    @Override
    public Boolean insertByBo(DocumentBo bo) {
        Document add = BeanUtil.toBean(bo, Document.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setDocumentId(add.getDocumentId());
        }
        return flag;
    }

    /**
     * 修改文件信息
     */
    @Override
    public Boolean updateByBo(DocumentBo bo) {
        Document update = BeanUtil.toBean(bo, Document.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Document entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除文件信息
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public boolean splitFileAndSend(String fileName) {
        ExecutorService pool = Executors.newFixedThreadPool(15);
        // 获取用户主目录路径并拼接文件名
        String filePath = System.getProperty("user.home") + "\\Desktop\\HighSpeedFlow\\file\\" + fileName;
        //String filePath = System.getProperty("user.home") + "/Desktop/HighSpeedFlow/file/" + fileName;
        // 创建File对象
        File file = new File(filePath);
        // 创建FileInputStream对象
        try (FileInputStream fis = new FileInputStream(file)) {
            int bytesRead;         //用于存储每次读取的字节数
            Random random = new Random();
            PortDataHandler handler = new FilePortDataHandler();
            int count = 0;
            // 循环读取直到文件末尾
            while (true) {
                int size = 56 + random.nextInt(1024 - 64);
                byte[] buffer = new byte[size];             // 初始化缓冲区
                byte[] finalBuffer = new byte[size + 8];
                bytesRead = fis.read(buffer);
                if(bytesRead == -1) {
                    //读完了
                    break;
                }
                //目的端口号 16位
                int port0 = random.nextInt(16);
                short outport = (short) (1 << port0);
                //CRC校验码 16位
                byte[] crc = generateCRC(buffer);
                //优先级 3位
                byte priority = (byte) random.nextInt(8);
                //文件id 8位
                byte fileId = fileId0++;
                //文件包序号5位
                // 将count的低五位提取出来
                int countLowFive = count & 0x1F; // 0x1F的二进制是00011111，用于与操作提取低五位
                // 将priority的低三位提取出来，并左移五位
                byte priorityLowThree = (byte)(priority & 0x07); // 0x07的二进制是00000111，用于与操作提取低三位
                byte countShifted = (byte)(countLowFive << 3); // 左移三位
                // 将两个值拼接在一起
                byte result = (byte)(countShifted | priorityLowThree);

                int port = random.nextInt(16);

                DataFrame dataFrame = new DataFrame();
                dataFrame.setCrcCode(Arrays.toString(crc));
                dataFrame.setInport((long) port);
                dataFrame.setDocumentId((long) fileId);
                dataFrame.setLength((long) size+8);
                dataFrame.setSendState(1L);
                dataFrame.setSequenceNumber((long) result);
                dataFrame.setPriority((long) priority);
                dataFrame.setSendTime(new Date());
                dataFrameMapper.insert(dataFrame);
                //
                finalBuffer[0] = (byte) outport;
                finalBuffer[1] = (byte)(outport >>8);
                finalBuffer[2] = crc[0];
                finalBuffer[3] = crc[1];
                finalBuffer[4] = result;
                finalBuffer[5] = fileId;
                int frameId = dataFrame.getDataFrameId();
                finalBuffer[6] = (byte) (frameId & 0xFF);
                frameId = frameId >> 8;
                finalBuffer[7] = (byte) (frameId & 0xFF);
                for (int i = 0; i < size; i++) {
                    finalBuffer[i+8] = buffer[i];
                }
                // 处理读取到的字节
                fileName = String.valueOf(System.currentTimeMillis());
                handler.send(finalBuffer, port, fileName);
                count++;
                String finalFileName = fileName;
                pool.submit(() -> {
                    FilePortDataHandler h = new FilePortDataHandler();
                    try {

                        h.createOutFile(buffer, port, finalFileName);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
                // 打印信息，表示已处理的字节
                System.out.println("Processed " + bytesRead + " bytes");
            }
            return true; // 文件成功处理完毕
        } catch (IOException e) {
            e.printStackTrace();
            return false; // 处理文件时发生异常
        }
    }

    @Override
    public String testUSB() {
        FilePortDataHandler handler = new FilePortDataHandler();
        for(int i = 0; i < 16; i++) {
            int fileCount = handler.countBinFiles(i);
            while (fileCount > 0) {
                byte[] content = handler.receive(i);
                System.out.println(content.toString());
                fileCount--;
            }
        }
        return "usd";
    }

    // CRC-16的多项式，这里使用的是CRC-16/X-25的多项式
    private static final int POLYNOMIAL = 0x1021;

    // CRC-16的初始值
    private static final int INITIAL_VALUE = 0xFFFF;

    // 16位CRC校验码的生成函数，返回2字节的数组
    public static byte[] generateCRC(byte[] data) {
        int crc = INITIAL_VALUE; // 以初始值开始

        for (byte b : data) {
            crc ^= b & 0xFF; // 将数据字节与CRC值进行异或操作

            for (int i = 8; i != 0; i--) { // 处理8位数据
                if ((crc & 0x0001) != 0) {
                    crc >>= 1;
                    crc ^= POLYNOMIAL;
                } else {
                    crc >>= 1;
                }
            }
        }

        // 将CRC值转换为2字节的数组
        byte[] crcBytes = new byte[2];
        crcBytes[0] = (byte) ((crc >> 8) & 0xFF); // 高字节
        crcBytes[1] = (byte) (crc & 0xFF);         // 低字节

        return crcBytes;
    }
}
